#ifndef _GC_COMMON_MYSQL_H_
#define _GC_COMMON_MYSQL_H_

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#include "config.h"
#include "list.h"

static inline char * gc_explode_and_copy(char * dst, const char *src, const char delim) {
	char * p = strchr(src, delim);	
	size_t len = p == NULL ? strlen(src) : p - src;
	memcpy(dst, src, len);
	return p + 1;
}


gc_list_t * gc_get_config_by_mysql(const gc_config_t * config) {
	char sql[1024] = {0};
	char buffer[512] = {0};
	char addr[256] = {0};

	int i;
	my_ulonglong affected_rows;
	char * pos = config->data;
	gc_list_t * list = NULL;

	if(config->src != GC_SRC_MYSQL) {
		fprintf(stderr, "%s:%d: gc_config_t::src is not mysql!\n", __FILE__, __LINE__);
		return NULL;
	}

	//host:port:db:user:pass
	for(i = 0; i < 5; i ++) {
		pos = gc_explode_and_copy(buffer + 100 * i, pos, ':');
	}

	MYSQL * db = NULL;
	db = mysql_init(db);

	if(db == NULL) {
		 fprintf(stderr, "%s:%d: %u: %s\n", __FILE__, __LINE__, mysql_errno(db), mysql_error(db));
		 return list;
	}
	db = mysql_real_connect(db, buffer, buffer + 300, 
				buffer + 400, buffer + 200, atoi(buffer+100), NULL, 0);
	if(db == NULL) {
		fprintf(stderr, "%s:%d: connect to db failed\n", __FILE__, __LINE__);
		return list;
	}

	strcpy(sql, "set names utf8");
	if(mysql_real_query(db, sql, strlen(sql)) != 0) {
		fprintf(stderr, "Query: %s; return:%d; error:%s\n", sql, mysql_errno(db), mysql_error(db));
		mysql_close(db);
		return list;
	}

	MYSQL_STMT * stmt;

	stmt = mysql_stmt_init(db);
	if(!stmt) {
		fprintf(stderr, "%s:%d mysql_stmt_init out of memory", __FILE__, __LINE__);
		mysql_close(db);
		return list;
	}

	MYSQL_BIND bind[4];

	gc_get_hostaddr(addr, sizeof(addr));

	memset(sql, 0, sizeof(sql));
	strcpy(sql, "REPLACE INTO gc_client(group_name,host,status) VALUES(?, ?, 1)");
	if(mysql_stmt_prepare(stmt, sql, strlen(sql))) {
		fprintf(stderr, "Query: %s; error:%s\n", sql, mysql_stmt_error(stmt));
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	memset(bind, 0, sizeof(bind));

	//group
	bind[0].buffer_type = MYSQL_TYPE_STRING;
	bind[0].buffer = (char *) config->group;
	bind[0].buffer_length = strlen(config->group);
	bind[0].is_null = 0;

	//host
	bind[1].buffer_type = MYSQL_TYPE_STRING;
	bind[1].buffer = (char *) addr;
	bind[1].buffer_length = strlen(addr);
	bind[1].is_null = 0;

	if(mysql_stmt_bind_param(stmt, bind)) {
		fprintf(stderr, "%s:%d mysql_stmt_bind_param failed : %s\n", 
				__FILE__, __LINE__, mysql_stmt_error(stmt));
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	if(mysql_stmt_execute(stmt)) {
		fprintf(stderr, "%s:%d mysql_stmt_execute failed: %s\n",
				__FILE__, __LINE__, mysql_stmt_error(stmt));
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	affected_rows = mysql_stmt_affected_rows(stmt);
	if(affected_rows < 1) {
		fprintf(stderr, "%s:%d affected_rows is 0\n",
				__FILE__, __LINE__);
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	mysql_stmt_reset(stmt);

	memset(sql, 0, sizeof(sql));
	strcpy(sql, "select `key`,`value`,`val_type`,`version` from gc_config where group_name = ?");

	if(mysql_stmt_prepare(stmt, sql, strlen(sql))) {
		fprintf(stderr, "Query: %s; error:%s\n", sql, mysql_stmt_error(stmt));
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	memset(bind, 0, sizeof(bind));
	//group
	bind[0].buffer_type = MYSQL_TYPE_STRING;
	bind[0].buffer = (char *) config->group;
	bind[0].buffer_length = strlen(config->group);
	bind[0].is_null = 0;

	if(mysql_stmt_bind_param(stmt, bind)) {
		fprintf(stderr, "%s:%d mysql_stmt_bind_param failed : %s\n", 
				__FILE__, __LINE__, mysql_stmt_error(stmt));
		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	if(mysql_stmt_execute(stmt)) {
		fprintf(stderr, "%s:%d mysql_stmt_execute failed: %s\n",
				__FILE__, __LINE__, mysql_stmt_error(stmt));

		mysql_stmt_close(stmt);
		mysql_close(db);
		return list;
	}

	char row_key[512] = {0};
	char row_value[4096] = {0};
	int row_val_type = 0;
	int row_version = 0;
	unsigned long length[4];
	my_bool error[4];
	my_bool is_null[4];

	memset(bind, 0, sizeof(bind));
	//key
	bind[0].buffer_type = MYSQL_TYPE_STRING;
	bind[0].buffer = (char*) row_key;
	bind[0].buffer_length = sizeof(row_key);
	bind[0].is_null = &is_null[0];
	bind[0].length = &length[0];
	bind[0].error = &error[0];

	bind[1].buffer_type = MYSQL_TYPE_STRING;
	bind[1].buffer = (char*) row_value;
	bind[1].buffer_length = sizeof(row_value);
	bind[1].is_null = &is_null[1];
	bind[1].length = &length[1];
	bind[1].error = &error[1];

	bind[2].buffer_type = MYSQL_TYPE_LONG;
	bind[2].buffer = (char *) & row_val_type;
	bind[2].is_null = &is_null[2];
	bind[2].length = &length[2];
	bind[2].error = &error[2];

	bind[3].buffer_type = MYSQL_TYPE_LONG;
	bind[3].buffer = (char*) &row_version;
	bind[3].is_null = &is_null[3];
	bind[3].length = &length[3];
	bind[3].error = &error[3];
	
	if(mysql_stmt_bind_result(stmt, bind)) {
		fprintf(stderr, "%s:%d mysql_stmt_bind_result failed: %s\n",
				__FILE__, __LINE__, mysql_stmt_error(stmt));
		mysql_close(db);
		mysql_stmt_close(stmt);
		return list;
	}

	int row_count = 0;
	list = gc_list_create();
	while(mysql_stmt_fetch(stmt) == 0) {
		row_count ++ ;	

		gc_list_push(list, 
				row_key, strlen(row_key),
				row_value, strlen(row_value),
				row_val_type, row_version);
	}

	mysql_stmt_close(stmt);

	mysql_close(db);
	return list;
}

#endif
